package com.cskaoyan.javase.oop3._5lambda._0introduction;

/**
 * Lambda 表达式是 JDK8 的一个新特性，可以取代接口的匿名内部类，写出更优雅的Java 代码。
 * 如果说匿名内部类实际上是局部内部类的更进一步，简化了局部内部类，那么Lambda就是匿名内部类更进一步，语法上更简洁了，代码更优雅了，是高端的玩法，是人上人的玩法。
 * 以上描述总体就说了三点：
 * 1.Lambda表达式仍然是局部内部类，是特殊的局部内部类，仍然定义在局部位置。而且局部内部类的注意事项，也一样存在。
 * 2.Lambda表达式在取代匿名内部类时，不是全部都取代
 *          而是取代接口的匿名内部类，而类的匿名内部类Lambda表达式是不能取代的。
 * 3.Lambda表达式是匿名内部类的更进一步，
 *          Lambda表达式得到的也不是一个类，而是一个对象，并且是接口的子类对象。
 *
 *  Lambda表达式简化接口的匿名内部类,注意什么接口都可以了,而是必须要求这个接口是功能接口(Functional Interface)
 *  功能接口: 接口中有且仅有一个必须要求子类实现的抽象方法的接口
 *  功能接口使用注解@FunctionalInterface标记,该注解可以标记和检验一个接口是否为功能接口
 *  思考:
 *          1.功能接口中只能有一个方法?
 *              不是,因为Java8中还有默认方法和静态方法,不需要子类实现
 *          2.功能接口中只能有一个抽象方法吗?
 *              不是,接口中有些抽象方法不需要子类实现.
 *                  Object类是Java中所有类的父类,如果这个抽象方法,可以把Object当中的实现作为抽象方法的实现
 *                  那这个抽象方法就不需要子类实现.
 * 功能接口有了后,我们就可以用Lambda表达式,创建出功能接口的子类对象
 *
 *  Lambda表达式的语法:
 *  () -> {}
 *  解释:
 *  (): 是功能接口中那个要必须实现的抽象方法的形参列表.如果形参有多个,那就需要全部写出来
 *  ->: 是一个"箭头",它是Lambda表达式的运算符,可以读作"goes to"
 *  {}: 是功能接口中那个要必须实现的抽象方法的重写方法体,这里是一个方法体,而不是类体
 *  注意:
 *      1.因为Lambda表达式只有一套用于方法重写的方法体和形参,所以只能表示重写一个方法
 *          所以功能接口中,才要求有且仅有一个必须要求子类实现的抽象方法
 *      2.{}是方法体,不是类体,这意味着Lambda表达式虽然表示一个接口的子类对象,但这个对象一定没有自身独有成员
 *          因为没办法定义.
 *
 * 在方法等局部位置，写上述语法后，肯定会报错。原因在于Java是强类型语言，任何变量都有它的数据类型，而直接写Lambda表达式语法，编译器是无从得知它的数据类型的——这个Lambda表达式创建了接口的子类对象，到底是哪个接口的子类对象呢？
 *
 * 所以我们需要帮助编译器，明确Lambda表达式所表示的对象的类型，这个过程称之为 "Lambda表达式的类型推断"。
 * 类型推断需要借助代码的上下文额外信息,主要有下列方式:
 *      1.可以直接用父接口引用接收,这是最简单的方式.
 *      2.使用Lambda表达式类型推断的特殊语法:
 *          ((父接口的名字)Lambda表达式).方法名(实参列表);
 *      借助方法来完成类型推断
 *      3.借助方法的返回值类型完成类型推断
 *      4.借助方法的形参数据类型完成类型推断
 *
 * 以上Lambda表达式的基本使用,就结束了.
 *
 * @since 16:25
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 写ITest接口的子类对象,用Lambda表达式
        ITest it = () -> {
            System.out.println("hello world!");
        };
        it.test();

        ((ITest) () -> {
            System.out.println("我是lambda表达式的实现!");
        }).test();

        method().test();

        method(new ITest() {
            @Override
            public void test() {
                System.out.println("我是匿名内部类的实现!");
            }
        });

        method(() -> {
            System.out.println("我借助方法的形参数据类型完成类型推断!");
        });

    }

    public static ITest method() {
        /*return new ITest() {
            @Override
            public void test() {
                System.out.println("我是匿名内部类的实现!");
            }
        };*/
        return () -> {
            System.out.println("我借助方法的返回值类型完成类型推断!");
        };
    }

    public static void method(ITest it) {
        it.test();
    }
}

@FunctionalInterface
interface ITest {
    void test();
}

class IAImpl implements IA {
    @Override
    public void test() {
        System.out.println("hello world!");
    }
}

@FunctionalInterface
interface IA {
    void test();

    default void test2() {
    }

    static void test3() {
    }

    // 写Object类当中equals方法实现的抽象方法
    boolean equals(Object obj);

    int hashCode();
}
/*
@FunctionalInterface
interface IA{}*/
/*
@FunctionalInterface
interface IA{
    void test();
    void test2();
}*/
